package processevent

// todo: 目前仅实现对于linux环境的支持
// todo: 后期可以参考yulong和其他技术，实现对于mac、windows等平台支持进程监控的效果

import (
	"cloud_worm/worm/client/monitor/kafka"
	"cloud_worm/worm/client/monitor/processevent/psnotify"
	"github.com/golang/glog"
	"fmt"
	"os"
	"strconv"
	"cloud_worm/worm/client/monitor/monitorlog"
	"context"
	"bytes"
	"github.com/astaxie/beego/logs"
)

// 需要回收的资源有：
// watcher
// producer
// Goroutine
type ProcessMonitor struct {
	watcher			*psnotify.Watcher

	producer 		kafka.KafProducer
	logFd 			*logs.BeeLogger

	localIP 		string
	cancel 			context.CancelFunc
}

func NewProcessMonitor(localIP string, producer kafka.KafProducer, logFd *logs.BeeLogger, cancel context.CancelFunc) *ProcessMonitor {
	w, err := psnotify.NewWatcher()
	if err != nil {
		glog.Fatalf(err.Error())
		return nil
	}

	return &ProcessMonitor{
		watcher: w,
		producer: producer,
		logFd: logFd,
		localIP: localIP,
		cancel: cancel,
	}
}

func (ps *ProcessMonitor) Loop(ctx context.Context) error {
	selfPid := strconv.Itoa(os.Getpid())

	go func(ps *ProcessMonitor) {
		glog.Infof("cmd_loop start for %s", ps.localIP)

		var sep = []byte("")
		var msgFlag = []byte("afocus_cmdlog")
		sl := make([][]byte, 0, 2)
		sl = append(sl, msgFlag)

		for {
			select {
			case ev := <- ps.watcher.Exec:
				p := &Process{}
				if flag, _ := p.Analyzer(selfPid, fmt.Sprintf("%d", ev.Pid), ps.localIP); flag == true {

					if b, err := p.MarshalJSON(); err == nil {
						if ps.logFd != nil {
							// 写log日志
							ps.logFd.Info("%s: %s", monitorlog.MonitorCmdLog, b)
						}
						if ps.producer != nil {
							// 写kafka
							sl = sl[:1]
							sl = append(sl, b)
							ps.producer.AsyncSend(bytes.Join(sl, sep), "")
						}
					}
				}

			case err := <- ps.watcher.Error:
				glog.Errorf("process monitor error: %s", err.Error())
			case <- ctx.Done():
				glog.Errorf("server Done stop cmd monitor loop ......")
				ps.watcher.Close()
				return
			}
		}
		glog.Errorf("cmd_loop end for %s", ps.localIP)
	}(ps)

	return nil
}

func (ps *ProcessMonitor) Close()  {
	ps.cancel()
	return
}